package com.guapi.security.filter;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import com.guapi.dao.User;
import com.guapi.exception.SelfException;
import com.guapi.security.UserDetailImpl;
import com.guapi.util.BaseConstant;
import com.guapi.util.IpUtils;
import com.guapi.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IpUtils ipUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader("X-TOKEN");
        DateTime thisTime = DateUtil.date();
        try {
            String servletPath = request.getServletPath();
            //系统信息访问频率过高
            if (!servletPath.equals("system/info")) {
                ipUtils.recordIpIn(request);
            }
            if (token == null || token.isEmpty()) {
                chain.doFilter(request, response);
                return;
            }
            //System.out.println(token);
            JWTUtil.verify(token, BaseConstant.TOKEN_SIGNATURE);
            JWTValidator.of(token).validateDate(thisTime);
            JWT jwt = JWTUtil.parseToken(token);
            User user = JSONUtil.toBean(jwt.getPayload("user").toString(), User.class);
            String userKey = RedisUtil.getUserKey(String.valueOf(user.getId()));
            UserDetailImpl userDetail = (UserDetailImpl) redisTemplate.opsForValue().get(userKey);
            UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(userDetail, null, userDetail.getAuthorities());
            SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
            SecurityContextHolder.getContext().setAuthentication(userToken);
            chain.doFilter(request, response);
        } catch (ValidateException e) {
            //token已过期
            request.getSession().setAttribute("Expire", "true");
            response.setHeader("Error-Message", "token expired");
            response.setHeader("Access-Control-Expose-Headers", "Error-Message");
            response.sendError(403, "token expired");
            chain.doFilter(request, response);
        } catch (SelfException e) {
            e.printStackTrace();
            response.setHeader("Error-Message", e.getMessage());
            response.setHeader("Access-Control-Expose-Headers", "Error-Message");
            response.sendError(Integer.parseInt(e.getCode()), e.getMessage());
            chain.doFilter(request, response);
        } catch (RuntimeException e) {
            e.printStackTrace();
            response.setHeader("Error-Message", "未知错误！");
            response.setHeader("Access-Control-Expose-Headers", "Error-Message");
            response.sendError(500, "未知错误！");
            chain.doFilter(request, response);
        }
    }
}
